package filter;

import utils.SessionVar;
import utils.DBConnection;
import utils.TextUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;

import account.Account;
import account.AccountInfo;
import examinee.Examinee;
import examinee.ExamineeInfo;
import control.ComputerInfo;
import control.Computer;
import control.ControlVar;
import exam.TestPaperInfo;
import exam.TestPaper;
import exam.TestPaperGenerator;
import exam.ExamVar;

/**
 * Created by IntelliJ IDEA.
 * User: Shawn
 * Date: 2009-5-29
 * Time: 21:28:12
 */
public class SignInFilter implements Filter {

    private static final String ERROR_CODE = "error";

    public static final int ERROR_MANAGER = 1;
    public static final int ERROR_EXAMINEE = 2;
    public static final int ERROR_TEST_DONE = 3;

    public static final String SIGNIN_MANAGER = "/manager_signin";
    public static final String SIGNIN_EXAMINEE = "/examinee_signin";

    public static final String SIGNOUT_MANAGER = "/manager_signout";
    public static final String SIGNOUT_EXAMINEE = "/examinee_signout";

    public static final String LOGIN_PAGE_MANAGER = "/index.jsp";
    public static final String LOGIN_PAGE_EXAMINEE = "/login.jsp";

    public static final String INDEX_MANAGER = "/admin/index.jsp";
    public static final String INDEX_EXAMINEE = "/exam/getTestPaper.action";

    public static final String RESOURCE_MANAGER = "/admin";
    public static final String RESOURCE_EXAMINEE = "/exam";

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) srequest;
        HttpServletResponse response = (HttpServletResponse) sresponse;

        String uri = request.getRequestURI();
        boolean isSignInManager = uri.equals(SIGNIN_MANAGER);
        boolean isSignInExaminee = uri.equals(SIGNIN_EXAMINEE);
        boolean isSignIn = isSignInManager || isSignInExaminee;

        boolean isSignOutManager = uri.equals(SIGNOUT_MANAGER);
        boolean isSignOutExaminee = uri.equals(SIGNOUT_EXAMINEE);
        boolean isSignOut = isSignOutManager || isSignOutExaminee;

        boolean isExecutable = uri.indexOf(".jsp") != -1 || uri.indexOf(".action") != -1;
        boolean isLoginPage = uri.equals(LOGIN_PAGE_MANAGER) || uri.equals(LOGIN_PAGE_EXAMINEE);

        boolean pass = true;
        if (isSignIn) {
            pass = signin(request);
        }
        else if (isSignOut) {
            pass = signout(request);
        }
        else if (isExecutable && !isLoginPage) {
            pass = validate(request);
        }

        if (!pass) {
            int error_code = (Integer) request.getAttribute(ERROR_CODE);
            switch (error_code) {
                case ERROR_MANAGER:
                    sendTopRedirect(response, LOGIN_PAGE_MANAGER + "?error=" + ERROR_MANAGER);
                    break;
                case ERROR_EXAMINEE:
                    sendTopRedirect(response, LOGIN_PAGE_EXAMINEE + "?error=" + ERROR_EXAMINEE);
                    break;
                case ERROR_TEST_DONE:
                    sendTopRedirect(response, LOGIN_PAGE_EXAMINEE + "?error=" + ERROR_TEST_DONE);
                    break;
            }
            return;
        }

        if (isSignInManager) {
            response.sendRedirect(INDEX_MANAGER);
            return;
        }

        if (isSignInExaminee) {
            response.sendRedirect(INDEX_EXAMINEE);
            return;
        }

        if (isSignOutManager) {
            response.sendRedirect(LOGIN_PAGE_MANAGER);
            return;
        }

        if (isSignOutExaminee) {
            response.sendRedirect(LOGIN_PAGE_EXAMINEE);
            return;
        }

        chain.doFilter(srequest, sresponse);
    }

    private boolean validate(HttpServletRequest request) throws ServletException {
        HttpSession session = request.getSession();

        String uri = request.getRequestURI();
        boolean isManagerResource = uri.startsWith(RESOURCE_MANAGER);
        boolean isExamineeResource = uri.startsWith(RESOURCE_EXAMINEE);

        boolean isManagerLogined = isManagerResource && session.getAttribute(SessionVar.USER_ID) != null;
        boolean isExamineeLogined = isExamineeResource && session.getAttribute(SessionVar.EXAMINEE_ID) != null;

        if (isManagerResource && !isManagerLogined) request.setAttribute(ERROR_CODE, ERROR_MANAGER);
        if (isExamineeResource && !isExamineeLogined) request.setAttribute(ERROR_CODE, ERROR_EXAMINEE);

        return isManagerLogined || isExamineeLogined;
    }

    private boolean signout(HttpServletRequest request) {
        HttpSession session = request.getSession();
        session.invalidate();
        return true;
    }

    private boolean signin(HttpServletRequest request) throws ServletException {
        HttpSession session = request.getSession();
        session.invalidate();

        String uri = request.getRequestURI();
        boolean isManagerLogin = uri.equals(SIGNIN_MANAGER);
        boolean isExamineeLogin = uri.equals(SIGNIN_EXAMINEE);

        boolean signin = false;
        Connection con = new DBConnection(DBConnection.AutoCommiteOff).getConnection();

        try {
            if (isManagerLogin) signin = managerLogin(con, request);

            if (isExamineeLogin) signin = examineeLogin(con, request);

            con.commit();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            DBConnection.close(con);
        }

        return signin;
    }

    private boolean managerLogin(Connection con, HttpServletRequest request) throws Exception {
        HttpSession session = request.getSession();

        String account = request.getParameter("account");
        String password = request.getParameter("password");

        AccountInfo info = Account.getAccountInfo(con, account, password);
        if (info.getAid() == 0) {
            request.setAttribute(ERROR_CODE, ERROR_MANAGER);
            return false;
        }

        session.setAttribute(SessionVar.USER_ID, info.getAid());
        session.setAttribute(SessionVar.USER_NAME, info.getAname());
        session.setAttribute(SessionVar.USER_ACCOUNT, info.getAccount());
        session.setAttribute(SessionVar.USER_RIGHTS, info.getRights());
        return true;
    }

    private synchronized boolean examineeLogin(Connection con, HttpServletRequest request) throws Exception {
        HttpSession session = request.getSession();

        //computer setting
        String ip = request.getRemoteAddr();
        ComputerInfo cinfo = Computer.getComputer(con, ip);
        String zkzh = request.getParameter("zkzh");
        if (cinfo.getCid() == 0 || !cinfo.getZkzh().equals(zkzh)) {
            request.setAttribute(ERROR_CODE, ERROR_EXAMINEE);
            return false;
        }

        //examinee setting
        ExamineeInfo einfo = Examinee.getExaminee(con, zkzh, TextUtils.getZeroTime(System.currentTimeMillis()));
        if (einfo.getEid() == 0) {
            request.setAttribute(ERROR_CODE, ERROR_EXAMINEE);
            return false;
        }

        //set computer in use
        cinfo.setState(ControlVar.COMPUTER_STATE_INUSE);
        Computer.modiComputer(con, cinfo);

        //test paper
        TestPaperInfo tinfo = TestPaper.getLastTestPaper(con, einfo.getEid());

        if (tinfo.getState() == ExamVar.STATE_END || tinfo.getTime() >= ExamVar.TEST_TIME) {
            request.setAttribute(ERROR_CODE, ERROR_TEST_DONE);
            return false;
        }

        session.setAttribute(SessionVar.EXAMINEE_ID, einfo.getEid());
        session.setAttribute(SessionVar.EXAMINEE_NAME, einfo.getEname());
        return true;
    }

    private void sendTopRedirect(HttpServletResponse response, String url) throws IOException {
        PrintWriter out = response.getWriter();
        out.println("<script>");
        out.println("top.location = '" + url + "'");
        out.println("</script>");
    }

    public void destroy() {
    }
}
